package com.education.util;


import com.alibaba.fastjson.JSONArray;
import com.education.exception.BusinessException;
import com.education.base.ErrorReturnConstant;
import com.education.base.PublicResultConstant;

import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ObjectUtil {
    /**
     * 根据属性名获取属性值
     * */
    public static Object getFieldValueByName(String fieldName, Object obj) {
        // 得到类对象
        if (obj==null){
            return null;
        }
        Class userCla = (Class) obj.getClass();
        Class userCla2 = (Class) obj.getClass().getSuperclass();

        /* 得到类中的所有属性集合 */
        Field[] fs = userCla.getDeclaredFields();
        Field[] fs2=null;
        if(userCla2!=null) {
             fs2 = userCla2.getDeclaredFields();
        }
        for (int i = 0; i < fs.length; i++) {
            Field f = fs[i];
            f.setAccessible(true); // 设置些属性是可以访问的
            try {

                if (f.getName().endsWith(fieldName)) {
                    return f.get(obj);
                }
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }

        if(fs2==null){
            return null;
        }

        for (int i = 0; i < fs2.length; i++) {
            Field f = fs2[i];
            f.setAccessible(true); // 设置些属性是可以访问的
            try {

                if (f.getName().endsWith(fieldName)) {
                    return f.get(obj);
                }
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }



        // 没有查到时返回空字符串
        return null;
    }

    /**
     * 获取属性名数组
     * */
    public String[] getFiledName(Object o){
        Field[] fields=o.getClass().getDeclaredFields();
        String[] fieldNames=new String[fields.length];
        for(int i=0;i<fields.length;i++){
            System.out.println(fields[i].getType());
            fieldNames[i]=fields[i].getName();
        }
        return fieldNames;
    }

    /**
     * 获取属性类型(type)，属性名(name)，属性值(value)的map组成的list
     * */
    public static List getFiledsInfo(Object o){
        Field[] fields=o.getClass().getDeclaredFields();
        String[] fieldNames=new String[fields.length];
        List list = new ArrayList();
        Map infoMap=null;
        for(int i=0;i<fields.length;i++){
            infoMap = new HashMap();
            infoMap.put("type", fields[i].getType().toString());
            infoMap.put("name", fields[i].getName());
            infoMap.put("value", getFieldValueByName(fields[i].getName(), o));
            list.add(infoMap);
        }
        return list;
    }

    /**
     * 获取对象的所有属性值，返回一个对象数组
     * */
    public Object[] getFiledValues(Object o){
        String[] fieldNames=this.getFiledName(o);
        Object[] value=new Object[fieldNames.length];
        for(int i=0;i<fieldNames.length;i++){
            value[i]=this.getFieldValueByName(fieldNames[i], o);
        }
        return value;
    }

    /**
     *  计算返回数据序号
     */
    public static JSONArray getListInfoNumber(JSONArray record, Integer pageIndex,Integer pageSize) {
        for (int i = 0; i < record.size(); i++) {
            record.getJSONObject(i).put("indexNumber",(i+1)+(pageIndex*pageSize)-pageSize);
        }
        return record;
    }

    /**
     * 深拷贝List
     * @param src
     * @param <T>
     * @return
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public static <T> List<T> deepCopy(List<T> src) throws IOException, ClassNotFoundException {
        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
        ObjectOutputStream out = new ObjectOutputStream(byteOut);
        out.writeObject(src);

        ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
        ObjectInputStream in = new ObjectInputStream(byteIn);
        @SuppressWarnings("unchecked")
        List<T> dest = (List<T>) in.readObject();
        return dest;
    }

    /**
     * 更新相同对象相同字段所不同的值
     * @param source
     * @param target
     * @param <T>
     * @return
     * @throws Exception
     */
    public static <T> T updateDifferentValuesInObject(T source,T target) throws Exception {
        if (source==null||target==null){
            throw new Exception(PublicResultConstant.PARAM_ERROR);
        }
        if (!source.getClass().equals(target.getClass())){
            throw new Exception(ErrorReturnConstant.TWO_OBJECTS_ARE_DIFFERENT);
        }
        Class<? extends Object> sourceClazz = source.getClass();
        Class<? extends Object> targetUpdate = target.getClass();
        Field[] sourceField = source.getClass().getDeclaredFields();
        Field[] targetField = target.getClass().getDeclaredFields();
        for (Field sourceItem : sourceField) {
            sourceItem.setAccessible(true);
            //获取源对象字段名称及对应值
            String sourceNameKey = sourceItem.getName();
            if (sourceNameKey.equals("serialVersionUID")){
                break;
            }
            Object sourceValue = getClassValue(source,sourceNameKey);
            for (Field targetItem : targetField) {
                targetItem.setAccessible(true);
                //获取目标对象字段名称及对应值
                String targetNameKey = targetItem.getName();
                if (targetNameKey.equals("serialVersionUID")){
                    break;
                }
                Object targetValue = getClassValue(target,sourceNameKey);
                if (sourceNameKey.equals(targetNameKey)){
                    Class type=targetItem.getType();
                    if (sourceValue!=null){
                        //得到该属性的类型
                        if (!sourceValue.equals(targetValue)){
                            //找到与原对象相同的属性的set方法
                            Method m=targetUpdate.getMethod("set"+upperCase(targetNameKey),type);
                            //给该方法设置值
                            m.invoke(target,sourceValue);
                        }
                    }else{
                        //找到与原对象相同的属性的set方法
                        Method m=targetUpdate.getMethod("set"+upperCase(targetNameKey),type);
                        //给该方法设置值
                        m.invoke(target,sourceValue);
                    }
                }
            }
        }
        return target;
    }

    /**
     * 根据字段名称取值
     * @param obj
     * @param fieldName
     * @return
     */
    public static Object getClassValue(Object obj, String fieldName) throws BusinessException {
        if (obj == null) {
            return null;
        }
        try {
            Class<? extends Object> beanClass = obj.getClass();
            Method[] ms = beanClass.getMethods();
            for (int i = 0; i < ms.length; i++) {
                // 非get方法不取
                if (!ms[i].getName().startsWith("get")) {
                    continue;
                }
                Object objValue;
                try {
                    objValue = ms[i].invoke(obj, new Object[] {});
                } catch (Exception e) {
                    continue;
                }
                if (objValue == null) {
                    continue;
                }
                if (ms[i].getName().toUpperCase().equals(fieldName.toUpperCase())
                        || ms[i].getName().substring(3).toUpperCase().equals(fieldName.toUpperCase())) {
                    return objValue;
                }
            }
        } catch (Exception e) {
            throw new BusinessException("取方法出错！" + e.toString());
        }
        return null;
    }

    //首字母转大写，转小写就加32
    public static String upperCase(String str) {
        char[] ch = str.toCharArray();
        ch[0] = (char) (ch[0] - 32);
        return new String(ch);
    }
}
